/*========================================================================================================================================================================================================

 PROJEKT:  Wetterstation MFC Siegendorf v1.0final 
 ERSTELLER: Dieter Schneider,Ing.
 DATUM:     
			06.11.12  v1.0  finalVersion für Auslieferung - analog zu v021
			31.10.12  v0.21 setDateTime Funktion für RTC eingebaut um Uhrzeit/Datum stellen zu können. Dabei muss g_changeTime auf true gestellt werden.(#define...)
		    19.10.12  v0.20 Problem dass ON von Arduino 2 erkannt wird. Eventl unbekanntes Hardwareproblem. Daher workarround mit Set_g_state wird beim ersten toggeln
							von Run2 Led auf g_state = 3 gesetzt
			26.09.12  v0.20 Sicherheitsfix: System wird bei Schleifenabbruch aus Sim9000 über Arduino 2 neu gestartet. Alle Fehler sollten dann durch
		                        den Neustart korrigiert werden.
			25.09.12  v0.19  Bugfix aus v018 bei Zeile 520 Abbruchbedingung while Schleife geändert wegen Fehler. Nun wird die Schleife wirklich
							 beim 10 Durchlauf gem Bedingung verlassen.
			09.09.12  v0.18  wie 0.17b nur dass das Bitmuster des Graycodes für die Windrichtungsmessung auf realen Stand angepasst worden ist
							 ErrorCount bei while Schleife Sim9000 einkommentiert
							 Filterfunktion bei Windgeschwindigkeitsmessung eingebaut. Max Windgeschw. 99km/h
							 
			26.08.12  v0.17b  Windmessung mittels Statemachine und micros() (v017 mittles Interrupt verursachte Neustarts nach der 2. SMS )
			11.08.12  v0.16  inkl WerteArchiv
			07.08.12  v0.15  inkl Watchdog für Ard 2
			06.08.12  v0.14  div Bugfix bei logFile Send. (max Datum + Handynummer wird übertragen. 10h Leistungstest iO)
			02.08.12  v0.122 delay bei LogFile nach EndTransmission
            31.07.12  v0.121 serLCD + bugfixed 10sec Loop
            xx.07.12  v0.11 windspeed
            27.07.12  v0.104bug fixed getSMSNr wenn error dann sms nr auf 1 setzen
            26.07.12  v0.103 optWhile
            25.07.12  v0.102 final für Leistungstest
            24.07.12  v0.101 IC2 logFile
            16.07.12  v0.09
            13.07.12  v0.08
            11.07.12  v0.07
            10.07.12  v0.06
            08.07.12  v0.05
            06.07.12  v0.04
            02.07.12  v0.03
            02.07.12  v0.02
            01.07.12  v0.01
 
 FUNKTIONSBESCHREIBUNG:
 **********************
 
 Wetterstation zur Ermittlung folgender Größen:
 ----------------------------------------------
 
 Messdatenermittlung via Polling mit einstellbarer Pollfrequenz im Programmcode ( #define Pollinig in µS ) 

   -) Windgeschwindigkeit in m/s
   -) Windrichtung zB NNW, NNO usw
   -) Temperatur in °C
   -) Feuchte in %
   -) aktuelle Uhrzeit + Datum via I2C RealTimeClock
   -) bei SMS Empfang muss dem Absender die ermittelten Messwerte retourniert werden inkl Bildung von Archivwerten
   -) Archivwerte für 30min, 1std und 3Std Messwertdurchschnitte bzw max Werte in diesem Zeiraum
   -) Protokollierung der Anrufer, Ereignisse in LogFiles auf SD Card 
   
 Bedienung der Wetterstation:
 ----------------------------
 
       -) Ermittlung sämtlicher Messgrößen , RSSI und Netzbetreiber
       -) Ausgabe der Messdaten auf Display ( Windgeschwindigkeit,Windrichtung, Temperatur, Feuchte, Durchschnittsgeschwindigkeiten alle, RSSI, Netzbetreiber) durch toggelndes Display zB alle 5sec
       -) Bei SMS Eingang Antwort dem Absender mit den ermittelten Messwerten
       -) Bildung von Wertearchiven für Durchschnittswerte bzw max Werte
       -) Protokollierung der Anrufernummer auf SD Card
       -) direkte Kommunikation mit GPRS Shield möglich über Software Serielle Schnittstelle
       -) Protokollierung von Eventl wie SMS Versand und Error Codes immer mittels Timestamp 
	   -) Watchdogfunktion für Arduino 2
       
     

       
       
       
       RJ45 Buchse Hardware Serielle Schnittstelle:
       --------------------------------------------
       Diese dient zum Programmieren bzw zur Kommunikation mit dem Arduino im Debug Mode. ( Ein und Ausgabe von Werten - Lese Schreibfunktion )
       
       RJ45 Buchse Software Serielle Schnittstelle:
       --------------------------------------------
       Diese zur direkten Kommunikation mit dem GPRS Shield. Diese Schnittstelle ist direkt an die Software Serial angeschlossen! Man kann auch die Kommunikation zwischen Arduino und GPRS 
       mitlauschen ggf protokollieren mit einem entsprechenden Terminalprogramm.
      
       
       
   
       Antworten von GPRS Shield:
       *************************
        +CMTI: "SM",2    // bei SMS Eingang kommt diese Meldung
        +CMGR: "REC UNREAD","+436644213717","","12/06/23,11:20:36+08"    // wenn Nachricht ungelesen ist  
        +CMGR: "REC READ","+436644213717","","12/06/23,11:20:36+08"      // wenn Nachricht gelesen ist
        "AT+CMGS="+436644213717"\r"  // Arduino print Kommando für SMS Versand
        Netzbetreiber
        *************
        AT+COPS?                  //Kommando
        +COPS: 0,0,"bob"          //Antwort mit Value
        
        RSSI
        ****
        AT+CSQ                   //Kommando
        +CSQ: 15,0               //Antwort
        
        GPIO Setzen
        ***********
        AT+SGPIO = 0,1,1,1   // GPIO Pin1 auf High setzen
        Details siehe Sim9000At Command v1.03 auf Seite 151
       
	   
	    Darstellung Werteausgabe am LCD Display
       .......................................
        ||||||||||||||||  // Screen 1
        Wind 12,2m/s NNO
        Temp:21,2°C 88%
        
        ||||||||||||||||  // Screen 2
        Durschnitt 30min
        Wind  23,23m/s
        
        ||||||||||||||||  // Screen 3
        Durschnitt  1Std 
        Wind  10,23m/s
        
        ||||||||||||||||  // Screen 4
        Durschnitt  3Std 
        Wind   5,23m/s
        
        ||||||||||||||||  // Screen 5
        max Wind Speed 
        30min v=23,23m/s
        
        ||||||||||||||||  // Screen 6
        max Wind Speed 
        60min v=23,23m/s
        
        ||||||||||||||||  // Screen 7
        Empfang(RSSI)=23
        Netz ="bob"
        
        ||||||||||||||||  // Screen 8
        Betriebsstunden
        Std:123456789:59
        
        ||||||||||||||||  // Screen 9
        MFC Siegendorf 
        DSchneider v0.09
 
 PROGRAMMBESCHREIBEUNG:
 **********************
 inkl SMS Kommunikation der Messwerte
 inkl SHT15 Programm
 inkl LoopRate für gezielte Messwerterfassung auf definierbare Zeitgröße
 inkl Erfassung Windrichtung
 inkl Erfassung der RUN Debug Schalter und Taster
 inkl Ausgabe von Statuszustände auf den Leds am IO Expander Output
 inkl RSSI und Netzbetreibername
 inkl Statusleds GSM on, incomming sms, sending sms, networkfoung, no network,v0.07
 inkl RTC  v0.08
 inkl Betriebsstundenzähler v0.08
 inkl Ausgabe auf Display   v0.09
 inkl export over I2C Write to Sd card v0.101
 inkl write to SD Card on Arduino #2 ==> Slave Firmware v0.05
 inkl LCD I2C Ausgabe
 inkl Watchdog v015
 inkl Windmessung 
 inkl Wertearchive v016

 
 
 
 

 
 
 
 Arduino Anschlussbelegung
 *************************
 
 A0  
 A1  
 A2  
 A3  
 A4  I2C SDA
 A5  I2C SCL 
 D0  
 D1  
 D2  Messung Windgeschwindigkeit 
 D3  
 D4  ON Arduino 1
 D5  Power On/Off GPRS
 D6  RX GPRS
 D7  TX GPRS
 D8  sclkPin SHT15
 D9  dataPin SHT15
 D10 SIM900 Reset Information von System 2 bei Fehler Auftritt
 D11 Reset Arduino 2
 D12 Eingang RUN Led Arduino 2
 D13 Eingang ON Arduino 2
 
=========================================================================================================================================================================================================*/


#include <SoftwareSerial.h> 
#include <Wire.h>
#include <Sensirion.h>
#include <stdio.h>
#include <string.h>
#include <LiquidCrystal_I2C.h>
#define terminator 10                                                                 // DEC Wert für ein CR um die While Schleife verlassen zu können
#define DS1307_ADDRESS 0x68                                                           // I2C Adresse RTC
#define ONPin  13																	  // Pin Nr für Eingang Arduino 2 ist an
#define RUNPin 12																      // Pin Nr für Eingang Arduino 2 RUN Led
#define Reset  11																	  // Pin Nr für Ausgang Reset Arduino 2 ( Reset bei LOW - must be normal HIGH )
#define setRTC 0																	  // 1 für einstellen der RTC / 0 für Normalbetrieb
LiquidCrystal_I2C lcd(0x38);  // Set the LCD I2C address
const unsigned long Polling     =  100000;//125000;                                   // Wert für Polling in µS Sensorwerte
//const unsigned long Polling_GSM = 1000000;                                          // Wert für Polling in µS RSSI & Netzwerk
SoftwareSerial GPRS(6, 7);                                                            // definiert PortNr 6 und  7 RX und TX



//-------------------------------------------------------------Globale Variablen --------------------------------------------------------------------------------------------------------------------------
//Globale Var  funktionsübergreifend
boolean g_error=false;                                                                  //wird true gesetzt sobald ein Fehler erkannt wird. Dient zur Anzeige auf Led.Fehlercode wird separat auf SD Karte geschrieben
//Globale Var für Function SIM9000()
String g_IncDataSerial = "";                                                            // a string for incomming text from GPRS shield over software serial
String g_rssi_val="#";                                                                   // String für rssi Wert 
String g_Netzbetreiber="#";                                                              // String für Netzbetreiber
boolean g_GSM_on=false;
boolean g_network_found=false;
boolean g_no_network=true;
boolean g_incomming_sms=false;
boolean g_sending_sms=false;
//boolean g_write_sd_card=false;

//Globale Var für Function SHT15()
const uint8_t dataPin =  9;                                                           // SHT serial data
const uint8_t sclkPin =  8;                                                           // SHT serial clock

Sensirion sht = Sensirion(dataPin, sclkPin);
     
uint16_t g_rawData;
float g_temperature;
float g_humidity;
float g_dewpoint;

//Globale Var für Function I2C IO Expander Eingänge
byte g_inputsPA=0,g_inputsPB=0,g_outputsPA=0;                                           // ByteWert für Eingänge IOExpander bzw Ausgänge des IO Expander
String g_richtung ="";                                                                  // Übergabevariable Windrichtung für SMS Antwort bzw Display
boolean g_RUN=false,g_DEBUG=false,g_Taster=false;                                       // Var für Schalterzustände bzw Taster

//Globale Var für Function loop()
//unsigned long g_ActualTime = 0;                                                        // Zeitwert    
unsigned long g_StartTime = 0;                                                         // Startwert für Microsekungen zur LooprateMessung                                                   
unsigned long g_EndTime   = 0;                                                         // Endwert für Microsekungen zur LooprateMessung    
unsigned long g_CounterRate=0;
//unsigned long g_CounterRate_GSM=0;
boolean g_InitialLoop = false;                                                         // false für neue LoopRate kann g_CounterRate zugewiesen werden; true für Wert ist zugewiesen
unsigned long g_LoopRate = 0;
//unsigned long g_LoopRate_GSM = 0;
boolean g_running=false;                                                               // toggle Merker welcher im Sekundentakt ein aus geschaltet wird und die Abarbeitung des Programmes symbolisiert.
//boolean gsmState_toggle=false;                                                         // toggle Var zum abrufen von rssi und Netzbetreibername
byte g_gsm_toggle_count = 0;                                                           // Zähler sodass in sec Loop alle 10sec AT Kommandos zur RSSI bzw Netzabfrage geschickt werden
byte g_rssi_netz_simDel = 0;                                                           // Zähler für das nacheinaner Ausführen für RSSI netzbetreiber und SIM Karte löschen

//Globale Var für Function RTC
String g_datum="",g_uhrzeit="";                                                        //aktuelle Uhrzeit und Datum von RTC
boolean g_get_start_time=true;                                                         // wird false bei ersten Programmablauf
byte g_minute_aktuell=0,g_minute_vergangen=0,g_BSZ_counter_min = 0;                    // Var zum speichern der Minuten bzw Zählerstände
signed int g_BSZ_counter_std=0;                                                        // Stundenzähler 


//Globale Var für Function I2CLCD
byte g_LCD=0;                                                                          // Zählvariable für LCD
byte g_lcd_loop=0;																       // Zähler für das nächste Anzeigefenster am LCD Display

//Globale Var für Funktion logFile I2C
boolean g_SMS_Versand_bool = false;
boolean g_Error_bool=false;
String g_SMS_Versand="";
String g_handynummer="";
String g_Error_Info="";
String g_uhrzeit_sd="";

//Globale Var für Funktion windSpeed
float g_wind=0;


//Globale Var für Watchdog
byte g_state=1;																			//Zustand für Watchdog Statemachine
byte g_kill =0;																			//Zähler für Reset Arduino 2
byte g_WatchCount=0;
boolean g_runToggle = false;
byte g_runningCount=0;
boolean Set_g_state = true;	//workarround für Problem dass ON2 Status gelesen werden kann

//Globale Var für WerteArchiv
boolean g_Archiv_first_Start=false;														// wird true beim ersten Starten des Archives
boolean g_calc_archiv = false;															//true wenn Archiv berechnet wird dann Led an
int g_ArchivCounter=0;																	//erhöhte sich jede Minute
byte g_state_archiv=1;																	//var für Statemachine WerteArchiv
float g_wind_archiv30=0;																	//Wind Durchschnittswerte für einzelnen Archive
float g_wind_archiv60=0;																	//Wind Durchschnittswerte für einzelnen Archive
float g_wind_archiv180=0;																	//Wind Durchschnittswerte für einzelnen Archive
float g_wind30=0;
float g_wind60=0;
float g_wind180=0;
float g_wind_max30=0;
float g_wind_max60=0;
float g_vmax30=0;
float g_vmax60=0;
float g_vmax30_pre=0;
float g_vmax60_pre=0;











//-------------------------------------------------------------Setup Routine wird nur einmal aufgerufen ---------------------------------------------------------------------------------------------------
void setup()
{
  lcd.begin(16,2);    														           // initialize the lcd
  lcd.clear();
  lcd.setCursor ( 0, 0 );        // ( Spalte / Zeile )
  if(setRTC)
  { 
	lcd.print("setRTC OK"); 
	lcd.setCursor ( 0, 1 );        
	lcd.print ("reload Firmware");
	setDateTime();
	while(1)
	{
	 // do nothing because you must reload your Firmware with setRTC = 0!
	}
  }
  lcd.print("  Willkommen!  ");  
  lcd.setCursor ( 0, 1 );        
  lcd.print (" starte System "); 
  GPRS.begin(19200);                                                                   // Software Serial Baudrate für Kommunikation zwischen Arduino und GPRS Shield
  Serial.begin(19200);                                                                 // HardwareSerial für Kommunikation mit PC
  pinMode(10,OUTPUT);                                                                  // Pin Signalisiert HIGH Signal wenn SIM9000 Probleme veruracht
  digitalWrite(10,LOW);								         // LOW is default und bedeutet alles in Ordnung
  pinMode(5, OUTPUT);                                                                  // start up procedure for gprs shield to power up
  digitalWrite(5,LOW);
  delay(1000);
  digitalWrite(5,HIGH);
  delay(2500);
  digitalWrite(5,LOW);
  delay(3500);                                                                         // end of start up procedure 
  g_GSM_on=true;                                                                       // GSM Modul eingeschaltet
  GPRS.print("AT+SGPIO=0,1,1,1\r");                                                    // setze GPIO Pin Nr 1 auf High
  delay(2000);                                                                         // warte OK ab damit nächster Befehl übertragen werden kann
  GPRS.print("AT+CPIN=6242\r");                                                        //  AT Command für die  PinCode Eingabe
  g_InitialLoop = false;
  
  Wire.begin();                                                                        // wake up I2C bus für Eingänge
  // setup addressing style
  Wire.beginTransmission(byte(0x20));                                                  // 0x20 ist die I2C Adresse default von den Eingängen
  Wire.write(byte(0x12));                                                              // set MCP23017 memory pointer to GPIOA 0x12 address / GPIOB 0x13
  Wire.write(byte(0x20));                                                              // use table 1.4 addressing
  Wire.endTransmission();
  
  Wire.begin();                                                                        // wake up I2C bus für Eingänge
  // setup addressing style
  Wire.beginTransmission(byte(0x20));                                                  // 0x20 ist die I2C Adresse default von den Eingängen
  Wire.write(byte(0x13));                                                              // set MCP23017 memory pointer to GPIOA 0x12 address / GPIOB 0x13
  Wire.write(byte(0x20));                                                              // use table 1.4 addressing
  Wire.endTransmission();
  
  Wire.begin();                                                                        // wake up I2C bus für Ausgänge
  // setup addressing style
  Wire.beginTransmission(byte(0x27));                                                  // 0x27 ist die I2C Adresse default von den Eingängen
  Wire.write(byte(0x12));
  Wire.write(byte(0x20));                                                              // use table 1.4 addressing
  Wire.endTransmission();
  // set I/O pins to outputs
  Wire.beginTransmission(byte(0x27));
  Wire.write(byte(0x00));                                                              // IODIRA register
  Wire.write(byte(0x00));                                                              // set all of bank A to outputs
  Wire.write(byte(0x00));                                                              // set all of bank B to outputs
  Wire.endTransmission();
  Wire.beginTransmission(byte(0x27));
  Wire.write(byte(0x12));                                                              // GPIOA
  g_outputsPA = byte(0b00000000);                                                      // alle Outputpins auf LOW
  Wire.write(g_outputsPA);                                                             // schreibe Ausgänge von PortA
  Wire.endTransmission();
  
  //GPRS.print("AT+CMGR=1\r");
  //delay(2000);
  
  pinMode(ONPin, INPUT);
  pinMode(RUNPin, INPUT);
  pinMode(Reset, OUTPUT);
  digitalWrite(Reset,LOW);																//auf LOW damit Arduino 2 nicht resetet wird => reset bei HIGH
  pinMode(4,OUTPUT);
  digitalWrite(4,HIGH);																	// Arduino 1 ist ON
  pinMode(2,INPUT); 																	// Eingang für Windsensor
}



//-------------------------------------------------------------Beginn Hauptprogramm ----------------------------------------------------------------------------------------------------------------------
void loop()
{
  g_StartTime = micros();
  SIM9000();
  g_CounterRate++;                                                                    //für Polldauer zur Sensorabfrage
  g_EndTime = micros();
  
  if (digitalRead(RUNPin))															 // Watchdogüberprüfung von Arduino 2 ob running Eingang toggelt
	{
		if (!g_runToggle)
		{
		 g_runningCount++;
		}
		g_runToggle = true;
	}
	
  if (!digitalRead(RUNPin))
	{
		if (g_runToggle)
		{
		 g_runningCount++;
		 if(Set_g_state)
		 {
			g_state=3;
			Set_g_state = false;
		 }
		}
		g_runToggle = false;
		
	}
  
  if (g_CounterRate > 0 ) g_LoopRate =Polling/(g_EndTime - g_StartTime);
  
  if (g_CounterRate > g_LoopRate)                                                     			 // Erfassen der phys. Messwerte ==> Polling ca 1sec
  {
   g_gsm_toggle_count++;
   SHT15();
   IOExpanderInOut();
   RTC();
   g_wind=WindSpeed(); // messe die Windgeschwindigkeit in km/h
   //+++++ DEBUG Windgeschwindigkeit und Windrichtung
   // Serial.print("Windgeschwindigkeit: ");
   // Serial.print(g_wind);
   // Serial.print("\t");
   // Serial.print("Windrichtung: ");
   // Serial.println(g_richtung);
   //+++++ DEBUG Ende
   I2CLCD();
   WerteArchiv();
   // Serial.print("g_runningCount ");
   // Serial.print(g_runningCount);
   // Serial.print("digitalRead(ONPin)");
   // Serial.println(digitalRead(ONPin));
   g_WatchCount++;
   if (g_state<=2)
   {
    Watchdog();
   }
   if ((g_WatchCount >= 20) && (g_state >= 3))														// nach 20 Durchläufen und wenn Ard2 ist running
   {
    Watchdog();																		 				// alle 20 Durchläufe ca 10sec Watchdog aufrufen
	g_WatchCount = 0;
   }
   else if (g_state <= 2)
   {
    g_WatchCount = 0;
   }
   if (g_SMS_Versand_bool)
   {
	logFile(g_datum,g_handynummer); 
	g_SMS_Versand_bool=false;
   }
   g_CounterRate = 0;
   g_running = !g_running;                                                                         // toggle von 0 auf 1 und 0 ==> wenn kann sekündliches toggeln feststellbar ist, dann ist der µC abgestürzt.
   if (g_gsm_toggle_count >=20)                                                                    // run Led muss 10x Blinken (entspricht ca 10sec) dann efolgen die GPRS Commandos
   {
     g_rssi_netz_simDel++;                                                                         // Zähler fürs nacheinander ausführen der AT Befehle
     //logFile("Test","+436641234567");

     if (g_rssi_netz_simDel==1)     //if true
     {
       GPRS.print("AT+CSQ\r");                                                                      //  AT Command für rssi Value
	   //delay(1000);
     }
     else if (g_rssi_netz_simDel==2)
     {
       GPRS.print("AT+COPS?\r");                                                                   //  AT Command für Netzbetreiber
	   //delay(1000);
     }
     else if (g_rssi_netz_simDel==3)
     {
       GPRS.print("AT+CMGDA=");GPRS.print('"');GPRS.print("DEL ALL");GPRS.print('"');GPRS.print("\r");  //  AT Command für Lösche Simkarte ( kompletter Inhalt)
	   //delay(1000);
       g_rssi_netz_simDel=0;  
     }
       g_gsm_toggle_count=0;
   }
  }

  if (g_GSM_on==false && ((g_inputsPB | byte(0b11111110)) == byte(0b11111110)))                   // GPRS Modul ist ausgeschaltet und soll wieder eingeschaltet werden                  
  {
   GPRS_start();                                                                                  // rufe Function zum starten des GPRS Modules auf
  } 
   
  
}


//-------------------------------------------------------------Function für SMS Kommunikation der Messwerte ----------------------------------------------------------------------------------------------
void SIM9000()
{
   boolean writeSMS= false;
   boolean readSMS = false;
   while(GPRS.available()>0)                                                                   // if date is comming from softwareserial port ==> data is comming from gprs shield
  {
    boolean getCR = false;
    String Command = "";                                                                       // hier wird String für Kommunikation mit GPRS Shied übergeben AT+CMGR.....
    while(GPRS.available()>0 && !getCR)                                                        // reading data into char array if activity is on port an getCR is false ==> no CR have been send
    {
      char buffer=GPRS.read();                                                                 // writing data into char
      g_IncDataSerial += buffer;
      if (buffer == terminator) 
      {
        getCR = true;
      }
    }
    //Serial.println(g_IncDataSerial);                                                          // send string ( char array ) to hardware serial
    //Serial.print("\r");                                                                       // send a CR because it is missing
    boolean incSMS = false;
    
    if (g_IncDataSerial.substring(0,6)  =="+CMTI:")                                            // SMS wurde empfangen
    {
      incSMS = true;                                                                           // true wenn SMS empfangen wurde
      byte errorCount = 0;																	   // dient als While Schleifen Ausstieg wenn +cmgr nicht empfangen werden kann
      while(!writeSMS && (errorCount <= 10))											       // bis SMS gesendet worden ist oder ErrorCount größer gleich 10
																							   //*************** ÄNDERUNG AUS BUG v018*****************
																							   // 25.09.12 geändert weil Schleifenabbruch >=10 war anstatt <=10 und  anstatt 
																							   // ODER Verknüpfung eine UND Verknüpfung eingebaut
      {
	    errorCount++;	// am 11.09.12 wieder einkommentiert 
        if (!readSMS)
        {
          g_incomming_sms = true;
          IOExpanderInOut();
          String getSMS_Nr;
          
          
                                                                                                   // ermittle Stringlänge ob bei ungelesenser Nachricht die SMS Storage Nr  1 oder 2 stellig ist
          if (g_IncDataSerial.length() <=15 )                                                      // SMS Storage Number is one digit
          {
            //Serial.print("SMS Storage Nr und in if Anweisung 1stellig: ");
            getSMS_Nr = g_IncDataSerial.substring(12,13);                                          // hole Storage Nr aus Stringstelle 12-13
           //Serial.println(getSMS_Nr);
          }
          else if (g_IncDataSerial.length() <=16 )                                                 // SMS Storage Number is two digit
          { 
            //Serial.print("SMS Storage Nr und in if Anweisung 2stellig: ");
            getSMS_Nr = g_IncDataSerial.substring(12,14);                                          // hole Storage Nr aus Stringstelle 12-14
			//Serial.println(getSMS_Nr);
          }
          else 
          {
            //Serial.println("Error getting correct SMS Storage Number. ");                           // if stringlength is not one or two digit long. ==> error!! ==> Schwerwiegender Fehler
           //logFile("Error","Error getting correct SMS Storage Number.");          
            getSMS_Nr="1"; //wenn Nr nicht erkannt wird soll diese auf 1 gesetzt werden sodass SMS1 nochmals beantwortet wird. Im Normalfall soll es die Absendersms sein
            g_error = true;
            IOExpanderInOut();       
          } 
          
    
          if (incSMS == true)                                                                       // SMS wurde empfangen und SMS Storage Nr ist bekannt => Ermittlung von Absendernummer
          {
            Command = "AT+CMGR=";//1\r";
            Command += getSMS_Nr;
            Command += "\r";  
            GPRS.print(Command);                                                                    // schreibe Kommando zum lesen der SMS auf Storagenumber xy
            delay(2000);																			//wenn sich das GPRS Modul ausschalten würde, aber der Arduino nicht neu startet, dann muss hier das Delay ggf angepasst werden.(Empfangsbuffer overflow?)
            incSMS = false;
            readSMS = true;
          }
        }
        getCR = false;
        Command = "";                                                                              // hier wird String für Kommunikation mit GPRS Shied übergeben AT+CMGR.....
        g_IncDataSerial = "";
        while(GPRS.available()>0 && !getCR)                                                        // reading data into char array if activity is on port an getCR is false ==> no CR have been send
        {
          char buffer=GPRS.read();                                                                 // writing data into char
          g_IncDataSerial += buffer;
          if (buffer == terminator) 
          {
            getCR = true;
          }
        }
        if (g_IncDataSerial.substring(0,6)  =="+CMGR:" && g_IncDataSerial.length() >= 48)           // SMS Nachricht wurde abgerufen => Ermittle Absendernummer und Stringlänge ist größer gleich 48 ( wäre Ende Datum)
        {
          //                                         |hier Ende Datum     
          //+CMGR: REC UNREAD,+436644213717,,12/06/23,11:20:36+08
          String handynummer="";                                                                    // String für Handynummer    
          String str = "";                                                                          // lösche den String zur Nachrichtenübergabe
          Command ="";
          str = g_IncDataSerial;                                                                     // Übermittlung des Nachrichtenstrings
          int len = str.length()+1;                                                                // dyn Länge für das char Array
          char msgBuffer [len];                                                                    // dyn Bufferlänge von Länge msg String + 1 Zeichen für Nullterminator
          str.toCharArray(msgBuffer,len);                                                          // String von Zeichenkette GPRS wird in char Array zerlegt in var msgBuffer ( max länge wurde dyn definiert )
          char * pch;
          pch = strtok (msgBuffer,",");                                                            // Stringzerlegung bei jedem ,
          int i =0;
          while (pch != NULL)                                                                      // Solange bis keine "," mehr im String vorkommen
          {
            i++;                                                                                   // Zähler zur Bestimmung der Stringpaketgruppe. Paketgruppe 2 enthält die Handynummer
            if (i==2)                                                                               // Wenn Zählerstand hat die Paktegruppe 2 erreicht,dann wird die Handynummer der var übergeben
            { 
              handynummer = pch;
            }
            pch = strtok (NULL, ",");
          }
          g_incomming_sms=false;
          //IOExpanderInOut();
          Command  = "AT+CMGS=";
          Command += handynummer;
          Command += "\r";
		  g_handynummer = handynummer;
          // float wind = 12.65346367, wind30min = 7.5659890, wind1std = 5.345655, wind3std = 3.212039 ;
          // float vmax30 = 34.746356, vmax60 = 77.73653;
          g_sending_sms=true;
          IOExpanderInOut();
          GPRS.print(Command);                                                                     //AT Kommando für SMS Versand
          delay(1000);                                                                             // delay für OK
          GPRS.print("MFC Siegendorf:");GPRS.print(g_datum);GPRS.print(" ");GPRS.print(g_uhrzeit);GPRS.print(" aktuell ");GPRS.print(g_wind);GPRS.print("km/h aus ");GPRS.print(g_richtung);
          //GPRS.print("MFC Siegendorf:");GPRS.print(g_datum);GPRS.print(" ");GPRS.print(g_uhrzeit);GPRS.print(" BSZ ");GPRS.print(g_BSZ_counter_std);GPRS.print(":");GPRS.print(g_BSZ_counter_min);
          GPRS.print("[30min ");GPRS.print(g_wind);GPRS.print("km/h,1Std ");GPRS.print(g_wind60);GPRS.print("km/h,3Std ");GPRS.print(g_wind180);GPRS.print("km/h]vmax30min ");
          GPRS.print(g_vmax30);GPRS.print("km/h vmax60min ");GPRS.print(g_vmax60);GPRS.print("km/h T&F=");GPRS.print(g_temperature);GPRS.print("C/");GPRS.print(g_humidity);GPRS.print("%");
          GPRS.write(26);                                                                          // Strg+z für das Senden der Nachricht
          delay(3000); 
          g_error = false; // wenn true von Fehler getSMSNr dann hier wieder auf false setzen
          g_sending_sms=false;
          IOExpanderInOut();
          writeSMS=true;
          g_SMS_Versand_bool=true;    
        } 
        else   	// +CMGR: konnte nicht gelesen werden ==> eventl Übertragungsfehler bzw Probleme
	    {
         incSMS = true;			                                                        // incSMS auf True damit SMS neu abgerufen werden kann zum auslesen
         readSMS = false;			                                                // readSMS wird auf false gesetzt um die SMS erneut zu lesen
         errorCount++;				                                                //wird bei jedem Aufruf um 1 erhöht um dann irgendwann aus der WhileSchleife aussteigen zu können
        }
      }
      //Serial.print("SMS müsste verschickt worden sein");
      g_IncDataSerial ="";
												//****** Sicherheitsfix für v0.20  
      if(errorCount>=10)									//wenn es mehr als 10 Schleifendurchläufe gegeben hat, muss irgendwo ein Probleme							
												//mit dem SIM9000 Modul bestanden haben,daher wird System 1 über System 2 neu 
												//gestartet
      {
	digitalWrite(10,HIGH);								        // Resetbefehlt ( bei HIGH ) an Arduino 2 zum Neustart von Arduino 1
      }
    } 
    else incSMS = false;                                                                        // false wenn doch keine SMS angekommen ist
    if (g_IncDataSerial.substring(0,5)  =="+CSQ:" && g_IncDataSerial.length() >= 8)            // rssi Antwort von GPRS Shield gekommen. Stringlänge 8 geht bis 1 Ziffer RSSI Wert
    {
      //      |hier ende Stringlänge wie oben definiert    
      //+CSQ: 16,0
      g_rssi_val="";                                                                           // lösche String für rssi Wert  
      String str = "";                                                                         // lösche den String zur Nachrichtenübergabe
      str = g_IncDataSerial;                                                                   // Übermittlung des Nachrichtenstrings
      int len = str.length()+1;                                                                // dyn Länge für das char Array
      char msgBuffer [len];                                                                    // dyn Bufferlänge von Länge msg String + 1 Zeichen für Nullterminator
      str.toCharArray(msgBuffer,len);                                                          // String von Zeichenkette GPRS wird in char Array zerlegt in var msgBuffer ( max länge wurde dyn definiert )
      char * pch;
      pch = strtok (msgBuffer," ,");                                                           // Stringzerlegung bei jedem , und Leerzeichen
      int i =0;
      while (pch != NULL)                                                                      // Solange bis keine "," mehr im String vorkommen
      {
        i++;                                                                                   // Zähler zur Bestimmung der Stringpaketgruppe. Paketgruppe 2 enthält die Handynummer
        if (i==2)                                                                              // Wenn Zählerstand hat die Paktegruppe 2 erreicht,dann wird die Handynummer der var übergeben
        { 
          g_rssi_val = pch;
        }
        
        pch = strtok (NULL, " ,");
      }
    }
    
    if (g_IncDataSerial.substring(0,6)  =="+COPS:" && g_IncDataSerial.length() >= 12)          // Netzbetreiber Antwort von GPRS Shield gekommen. Stringlänge 12 geht bis 1 Ziffer Netzbetreiber Wert
    {
      //            |hier ende Stringlänge wie oben definiert    
      //+COPS: 0,0,"bob"
      
      String str = "";                                                                         // lösche den String zur Nachrichtenübergabe
      str = g_IncDataSerial;                                                                     // Übermittlung des Nachrichtenstrings
      int len = str.length()+1;                                                                // dyn Länge für das char Array
      char msgBuffer [len];                                                                    // dyn Bufferlänge von Länge msg String + 1 Zeichen für Nullterminator
      str.toCharArray(msgBuffer,len);                                                          // String von Zeichenkette GPRS wird in char Array zerlegt in var msgBuffer ( max länge wurde dyn definiert )
      char * pch;
      pch = strtok (msgBuffer,",");                                                            // Stringzerlegung bei jedem , 
      int i =0;
      while (pch != NULL)                                                                      // Solange bis keine "," mehr im String vorkommen
      {
        i++;                                                                                   // Zähler zur Bestimmung der Stringpaketgruppe. Paketgruppe 3 enthält den Netzbetreibernamen
        if (i==3)                                                                              // Wenn Zählerstand hat die Paktegruppe 3 wird der Netzbetreibername übergeben
        { 
          g_Netzbetreiber = pch;
          if (g_Netzbetreiber.substring(1,4)== "bob") {g_network_found = true;g_no_network=false;}
          else                                        {g_network_found = false;g_no_network=true;}
          IOExpanderInOut();
        }
        
        pch = strtok (NULL, ",");
      }
    }
    
    g_IncDataSerial = "";
  }
}
//--------------------------------------------------------------------Function  SHT15 -------------------------------------------------------------------------------------------------------------------
void SHT15() 
{
  float temperature=0,humidity=0;
 sht.measTemp(&g_rawData);                // sht.meas(TEMP, &g_rawData, BLOCK)
 temperature = sht.calcTemp(g_rawData);
 if (temperature < 100 ) g_temperature = temperature;                                 // schränkt den Wertebereich ein gegen Fehlmessungen
 sht.measHumi(&g_rawData);                // sht.meas(HUMI, &g_rawData, BLOCK)
 humidity = sht.calcHumi(g_rawData, g_temperature);
 if (humidity <= 100 ) g_humidity = humidity;                                        // schränkt den Wertebereich ein gegen Fehlmessungen
 g_dewpoint = sht.calcDewpoint(g_humidity, g_temperature);
 //logData();
}



//-------------------------------------------------------------Function logData SHT15 -------------------------------------------------------------------------------------------------------------------
void logData() 
{
 /*Serial.print("Temperature = ");   Serial.print(g_temperature);
 Serial.print(" C, Humidity = ");  Serial.print(g_humidity);
 Serial.print(" %, Dewpoint = ");  Serial.print(g_dewpoint);
 Serial.print(" RSSI=");           Serial.print(g_rssi_val);
 Serial.print(" Netzbetreiber=");  Serial.print(g_Netzbetreiber);
 Serial.print(" Datum=");          Serial.print(g_datum);
 Serial.print(" Uhrzeit=");        Serial.print(g_uhrzeit);
 Serial.print("Betriebsstundenzähler (std:min) =");Serial.print(g_BSZ_counter_std);Serial.println(g_BSZ_counter_min);
 */
}


//-------------------------------------------------------------Function IOExpander In Out --------------------------------------------------------------------------------------------------------------
void IOExpanderInOut()
{
  Wire.beginTransmission(byte(0x20));                                                   // 0x20 ist die I2C Adresse default von den Ausgängen
  Wire.write(byte(0x12));                                                               // set MCP23017 memory pointer to GPIOA 0x12 address / GPIOB 0x13
  Wire.endTransmission();
  Wire.requestFrom(0x20, 1);                                                            // request one byte of data from MCP20317
  g_inputsPA=Wire.read();                                                               // Byte für Porteingang
  
  Wire.beginTransmission(byte(0x20));                                                   // 0x20 ist die I2C Adresse default von den Ausgängen
  Wire.write(byte(0x13));                                                               // set MCP23017 memory pointer to GPIOA 0x12 address / GPIOB 0x13
  Wire.endTransmission();
  Wire.requestFrom(0x20, 1);                                                            // request one byte of data from MCP20317
  g_inputsPB=Wire.read();                                                               // Byte für Porteingang
  
                                                                                        // ermittle die Windrichtung aus 4bit Gray Code
                                                                                        //*********************************************
  switch (g_inputsPA | byte(0b11110000))                                                // letzten 4 Bits immer mit 1 maskieren und OR verknüpfen. Die ersten 4 Bits definieren die Windrichtung
  {                                                                                     // letzten 4 Bits definieren zB Schalter oder Taster
   case  byte(0b11111000):g_error=false;g_richtung="N";break; 
   case  byte(0b11110000):g_error=false;g_richtung="NNO";break; 
   case  byte(0b11110010):g_error=false;g_richtung="NO";break; 
   case  byte(0b11110110):g_error=false;g_richtung="ONO";break; 
   case  byte(0b11110100):g_error=false;g_richtung="O";break; 
   case  byte(0b11110101):g_error=false;g_richtung="OSO";break; 
   case  byte(0b11110111):g_error=false;g_richtung="SO";break; 
   case  byte(0b11110011):g_error=false;g_richtung="SSO";break; 
   case  byte(0b11110001):g_error=false;g_richtung="S";break; 
   case  byte(0b11111001):g_error=false;g_richtung="SSW";break; 
   case  byte(0b11111011):g_error=false;g_richtung="SW";break; 
   case  byte(0b11111111):g_error=false;g_richtung="WSW";break; 
   case  byte(0b11111101):g_error=false;g_richtung="W";break; 
   case  byte(0b11111100):g_error=false;g_richtung="WNW";break; 
   case  byte(0b11111110):g_error=false;g_richtung="NW";break; 
   case  byte(0b11111010):g_error=false;g_richtung="NNW";break; 
   default:               g_error=true;
						  //Serial.println("Cant getting Code for winddirections");
						  g_richtung="???";// Error Code Ausgabe für Error Event
						  break; // Error Code Ausgabe für Error Event
  }
  // Serial.print("Windrichtung g_richtung "); //Debug muss entfernt werden!
  // Serial.print(g_richtung); //Debug muss entfernt werden!
  // Serial.println(g_inputsPA,BIN); //Debug muss entfernt werden! 
  // Serial.print("PortB g_inputsPB "); //Debug muss entfernt werden!
  // Serial.println(g_inputsPB,BIN); //Debug muss entfernt werden! 
  if ((g_inputsPB | byte(0b11111110)) == byte(0b11111111))
  {
    g_GSM_on=true;                                                                      // GSM Modul eingeschaltet
  }
  else
  {
    g_GSM_on=false;                                                                      // GSM Modul ausgeschaltet
  }
   
                                                                                        // ermittle RUN oder DEBUG Mode bzw Debug Taster betätigt?
                                                                                        //*********************************************
  //Serial.print("(g_inputsPA | byte(0b00001111)) ");Serial.println((g_inputsPA | byte(0b00001111)) ,BIN);
  switch (g_inputsPA | byte(0b00001111))                                                // erste 4 Bits immer mit 1 maskieren und OR verknüpfen. Die letzten 4 Bits definieren die Schalter/Taster
  {                                                                                     // erste 4 Bits definieren die Windrichtung
   case  byte(0b01011111):g_error=false;break;                                          // keine Aktion da im RUN Mode der Taster keine Funktion hat                                                   
   case  byte(0b00011111):g_error=false;g_RUN=true;g_DEBUG=false;break;                 // RUN Mode gewählt
   case  byte(0b01101111):g_error=false;g_Taster=true;break;                            // DEBUG Taster gedrückt
   case  byte(0b00101111):g_error=false;g_DEBUG=true;g_RUN=false;g_Taster=false;break;  // DEBUG Mode gewählt
   case  byte(0b00001111):g_error=true;Serial.println("Not allowed state of bit values while reading IO Expander Inputs");break; // Error Code Ausgabe für Error Event ==> nicht erlaubtes Bitmuster was anliegen darf.( ein Schalter hat nur eine Stellung !! )
   default:               g_error=true;Serial.println("Not allowed state of bit values while reading IO Expander Inputs");break; // Error Code Ausgabe für Error Event ==> nicht erlaubtes Bitmuster was anliegen darf.( ein Schalter hat nur eine Stellung !! )
  }
  //Serial.print("Windrichtung ");Serial.print(g_richtung);Serial.print(" RUN ");Serial.print(g_RUN);Serial.print(" DEBUG ");Serial.print(g_DEBUG);
  //Serial.print(" Taster ");Serial.print(g_Taster);Serial.print(" Error ");Serial.println(g_error);
  
  
  byte output_set;
  //******************************************************************************
  if (g_running==true)                                                                  // toggle Run Led 
  {
    output_set = byte(0b00000001);
    g_outputsPA = g_outputsPA | output_set;
    Wire.beginTransmission(byte(0x27));
    Wire.write(byte(0x12));                                                              // GPIOA
    Wire.write(g_outputsPA);                                                             // schreibe Ausgänge von PortA
    Wire.endTransmission();
  }
  else
  {
    output_set = byte(0b00000001);
    g_outputsPA = g_outputsPA ^ output_set;
    Wire.beginTransmission(byte(0x27));
    Wire.write(byte(0x12));                                                              // GPIOA
    Wire.write(g_outputsPA);                                                             // schreibe Ausgänge von PortA
    Wire.endTransmission();
  }
  //******************************************************************************
  if (g_GSM_on==false) 
  {
    g_error = true;
    g_no_network = true;
    g_network_found = false; 
  }
  if (g_GSM_on==true)                                                                     // true sobald GSM on Prozedure abgeschlossen ist
  {
    g_error = false;                                                                      // wenn GPRS an dann error false
    output_set = byte(0b00000010);
    g_outputsPA = g_outputsPA | output_set;
    Wire.beginTransmission(byte(0x27));
    Wire.write(byte(0x12));                                                              // GPIOA
    Wire.write(g_outputsPA);                                                             // schreibe Ausgänge von PortA
    Wire.endTransmission();
  }
  else if ((g_GSM_on ==false) && (g_outputsPA|byte(0b11111101))==byte(0b11111111))        // kein Fehler liegt mehr vor , Led wird ausgeschaltet
  {
    g_error = true;                                                                       // true wenn GPRS Modul aus ist da nicht Normalzustand
    output_set = byte(0b00000010);
    g_outputsPA = g_outputsPA ^ output_set;
    Wire.beginTransmission(byte(0x27));
    Wire.write(byte(0x12));                                                              // GPIOA
    Wire.write(g_outputsPA);                                                             // schreibe Ausgänge von PortA
    Wire.endTransmission();
  }
  //******************************************************************************
  if (g_network_found==true)                                                             // true sobald nein netz vorliegt
  {
    output_set = byte(0b00000100);
    g_outputsPA = g_outputsPA | output_set;
    Wire.beginTransmission(byte(0x27));
    Wire.write(byte(0x12));                                                              // GPIOA
    Wire.write(g_outputsPA);                                                             // schreibe Ausgänge von PortA
    Wire.endTransmission();
  }
  else if ((g_network_found ==false) && (g_outputsPA|byte(0b11111011))==byte(0b11111111)) // network found
  {
    output_set = byte(0b00000100);
    g_outputsPA = g_outputsPA ^ output_set;
    Wire.beginTransmission(byte(0x27));
    Wire.write(byte(0x12));                                                              // GPIOA
    Wire.write(g_outputsPA);                                                             // schreibe Ausgänge von PortA
    Wire.endTransmission();
  }
  //******************************************************************************
  if (g_no_network==true)                                                                // true sobald kein netz vorliegt
  {
    output_set = byte(0b00001000);
    g_outputsPA = g_outputsPA | output_set;
    Wire.beginTransmission(byte(0x27));
    Wire.write(byte(0x12));                                                              // GPIOA
    Wire.write(g_outputsPA);                                                             // schreibe Ausgänge von PortA
    Wire.endTransmission();
  }
  else if ((g_no_network ==false) && (g_outputsPA|byte(0b11110111))==byte(0b11111111))        // kein network
  {
    output_set = byte(0b00001000);
    g_outputsPA = g_outputsPA ^ output_set;
    Wire.beginTransmission(byte(0x27));
    Wire.write(byte(0x12));                                                              // GPIOA
    Wire.write(g_outputsPA);                                                             // schreibe Ausgänge von PortA
    Wire.endTransmission();
  }
  //******************************************************************************
  if (g_incomming_sms==true)                                                             // true bei incomming sms
  {
    output_set = byte(0b00010000);
    g_outputsPA = g_outputsPA | output_set;
    Wire.beginTransmission(byte(0x27));
    Wire.write(byte(0x12));                                                              // GPIOA
    Wire.write(g_outputsPA);                                                             // schreibe Ausgänge von PortA
    Wire.endTransmission();
  }
  else if ((g_incomming_sms ==false) && (g_outputsPA|byte(0b11101111))==byte(0b11111111))        // keine incomming sms
  {
    output_set = byte(0b00010000);
    g_outputsPA = g_outputsPA ^ output_set;
    Wire.beginTransmission(byte(0x27));
    Wire.write(byte(0x12));                                                              // GPIOA
    Wire.write(g_outputsPA);                                                             // schreibe Ausgänge von PortA
    Wire.endTransmission();
  }
  //******************************************************************************
  if (g_sending_sms==true)                                                              // true bei sms versand
  {
    output_set = byte(0b00100000);
    g_outputsPA = g_outputsPA | output_set;
    Wire.beginTransmission(byte(0x27));
    Wire.write(byte(0x12));                                                              // GPIOA
    Wire.write(g_outputsPA);                                                             // schreibe Ausgänge von PortA
    Wire.endTransmission();
  }
  else if ((g_sending_sms ==false) && (g_outputsPA|byte(0b11011111))==byte(0b11111111))        // kein sms versand
  {
    output_set = byte(0b00100000);
    g_outputsPA = g_outputsPA ^ output_set;
    Wire.beginTransmission(byte(0x27));
    Wire.write(byte(0x12));                                                              // GPIOA
    Wire.write(g_outputsPA);                                                             // schreibe Ausgänge von PortA
    Wire.endTransmission();
  }
  //******************************************************************************
  if (g_calc_archiv==true)                                                        // true wenn Archiv gerade berechnet wird
  {
    output_set = byte(0b01000000);
    g_outputsPA = g_outputsPA | output_set;
    Wire.beginTransmission(byte(0x27));
    Wire.write(byte(0x12));                                                              // GPIOA
    Wire.write(g_outputsPA);                                                             // schreibe Ausgänge von PortA
    Wire.endTransmission();
  }
  else if ((g_calc_archiv==false) && ((g_outputsPA|byte(0b10111111))==byte(0b11111111)))        // Archiv ist bereits berechnet
  {
    output_set = byte(0b01000000);
    g_outputsPA = g_outputsPA ^ output_set;
    Wire.beginTransmission(byte(0x27));
    Wire.write(byte(0x12));                                                              // GPIOA
    Wire.write(g_outputsPA);                                                             // schreibe Ausgänge von PortA
    Wire.endTransmission();
  }
  //******************************************************************************
  if (g_error==true)                                                                     // globaler Fehler liegt an. Led solangen eingeschaltet bis Fehlerzustand wieder verlassen wird.
  {
    output_set = byte(0b10000000);
    g_outputsPA = g_outputsPA | output_set;
    Wire.beginTransmission(byte(0x27));
    Wire.write(byte(0x12));                                                              // GPIOA
    Wire.write(g_outputsPA);                                                             // schreibe Ausgänge von PortA
    Wire.endTransmission();
  }
  else if ((g_error ==false) && (g_outputsPA|byte(0b01111111))==byte(0b11111111))        // kein Fehler liegt mehr vor , Led wird ausgeschaltet
  {
    output_set = byte(0b10000000);
    g_outputsPA = g_outputsPA ^ output_set;
    Wire.beginTransmission(byte(0x27));
    Wire.write(byte(0x12));                                                              // GPIOA
    Wire.write(g_outputsPA);                                                             // schreibe Ausgänge von PortA
    Wire.endTransmission();
  }
}
//-------------------------------------------------------------GPRS Start wenn Modul abgestürzt oder unbeabsichtigt runterfährt---------------------------------------------------------------------------
void GPRS_start()
{
  digitalWrite(5,LOW);
  delay(1000);
  digitalWrite(5,HIGH);
  delay(2500);
  digitalWrite(5,LOW);
  delay(3500);                                                                         // end of start up procedure 
  GPRS.print("AT+SGPIO=0,1,1,1\r");                                                    // setze GPIO Pin Nr 1 auf High
  delay(2000);                                                                         // warte OK ab damit nächster Befehl übertragen werden kann
  GPRS.print("AT+CPIN=6242\r");                                                        //  AT Command für die  PinCode Eingabe
  delay(2000);                                                                         //warte OK ab
  IOExpanderInOut();
}

//-------------------------------------------------------------Funktion für RTC manuelle Zeiteinstellung--------------------------------------------------------------------------------------------------
void setDateTime()
{
  byte zero = 0x00;
  
  byte second =      00; //0-59
  byte minute =      49; //0-59
  byte hour =        17; //0-23
  byte weekDay =     3; //1-7
  byte monthDay =    31; //1-31
  byte month =       10; //1-12
  byte year  =       12; //0-99

  Wire.beginTransmission(DS1307_ADDRESS);
  Wire.write(zero); //stop Oscillator

  Wire.write(decToBcd(second));
  Wire.write(decToBcd(minute));
  Wire.write(decToBcd(hour));
  Wire.write(decToBcd(weekDay));
  Wire.write(decToBcd(monthDay));
  Wire.write(decToBcd(month));
  Wire.write(decToBcd(year));

  Wire.write(zero); //start 

  Wire.endTransmission();
}
//-------------------------------------------------------------Funktion für RTC setDateTime Konvertierung-------------------------------------------------------------------------------------------------------------
byte decToBcd(byte val)
{
// Convert normal decimal numbers to binary coded decimal
  return ( (val/10*16) + (val%10) );
}
//-------------------------------------------------------------Funktion für RTC Konvertierung-------------------------------------------------------------------------------------------------------------
byte bcdToDec(byte val)  
{
// Convert binary coded decimal to normal decimal numbers
  return ( (val/16*10) + (val%16) );
}
//-------------------------------------------------------------Funktion RTC-------------------------------------------------------------------------------------------------------------------------------
void RTC()
{
  boolean lock_counter = false;                                         // false sofern sich die Minutenwerte nicht verändert haben => es ist noch keine Minute vergangen
  // Reset the register pointer
  Wire.beginTransmission(DS1307_ADDRESS);
  byte zero = 0x00;
  Wire.write(zero);
  Wire.endTransmission();

  Wire.requestFrom(DS1307_ADDRESS, 7);

  int second = bcdToDec(Wire.read());
  int minute = bcdToDec(Wire.read());
  int hour = bcdToDec(Wire.read() & 0b111111); //24 hour time
  int weekDay = bcdToDec(Wire.read()); //0-6 -> sunday - Saturday
  int monthDay = bcdToDec(Wire.read());
  int month = bcdToDec(Wire.read());
  int year = bcdToDec(Wire.read());
  g_datum= "";                                                          // lösche Datumsstring für neuen Messwert
  g_datum   += monthDay;
  g_datum   += ".";
  g_datum   += month;
  g_datum   +=".";
  g_datum   += year;
  g_uhrzeit = "";                                                       // lösche Uhrzeitstring für neuen Messwert
  g_uhrzeit += hour;                        
  g_uhrzeit += ":";
  g_uhrzeit += minute;
  g_uhrzeit_sd = g_uhrzeit;
  g_uhrzeit += ":";
  g_uhrzeit += second;
  
  g_minute_aktuell = minute;                                                                                   // hole aktueller Minutenwert
  
  if (g_minute_aktuell != g_minute_vergangen ) lock_counter = true;                                            // sobald eine Minute vergangen ist dann wird lock_counter auf true gestellt um den BSZCounter zu erhöhen
  else                                         lock_counter = false;
  
  if (g_get_start_time==true)                                                                                  // nur Erfassung nur im ersten Durchlauf für Starttime
  {
   g_get_start_time=false;
   //Protolliere Startzeitpunkt Uhrzeit + Datum auf SD Card
   String Buffer="";
   Buffer+=g_datum;
   Buffer+=" ";
   Buffer+=g_uhrzeit;
   //Buffer+=" ";
   //Buffer+=handynummer;
   logFile("StartBSZ ",Buffer);
  }
  else
  {
    if (g_minute_aktuell > g_minute_vergangen && g_get_start_time == false && lock_counter==true)              // für Einstieg bei Minute 0 bis 58
    {
     g_BSZ_counter_min++;                                   // eine Minute ist vergangen ==> erhöhe Zähler
	 g_ArchivCounter++;										// eine Minute ist vergangen ==> erhöhe den Archivminutenzähler
	 g_wind_archiv30 = g_wind_archiv30+g_wind;				// Werte für jeweilige min Archiv => errechne jede Minute für Durschnittsbildung
	 g_wind_archiv60 = g_wind_archiv60+g_wind;				// Werte für jeweilige min Archiv => errechne jede Minute für Durschnittsbildung
	 g_wind_archiv180 = g_wind_archiv180+g_wind;			// Werte für jeweilige min Archiv => errechne jede Minute für Durschnittsbildung
     
    }
    if (g_minute_aktuell < g_minute_vergangen && g_get_start_time == false && lock_counter==true)              // für Einstieg bei Minute 59 dann sprung auf Minute 0 
    {
     g_BSZ_counter_min++;                                                                                       // eine Minute ist vergangen ==> erhöhe Zähler
	 g_ArchivCounter++;										// eine Minute ist vergangen ==> erhöhe den Archivminutenzähler
	 g_wind_archiv30 = g_wind_archiv30+g_wind;				// Werte für jeweilige min Archiv => errechne jede Minute für Durschnittsbildung
	 g_wind_archiv60 = g_wind_archiv60+g_wind;				// Werte für jeweilige min Archiv => errechne jede Minute für Durschnittsbildung
	 g_wind_archiv180 = g_wind_archiv180+g_wind;			// Werte für jeweilige min Archiv => errechne jede Minute für Durschnittsbildung
    }
  }
  if (g_BSZ_counter_min >=60)                                                                                  // 60min sind vergange
  {
   g_BSZ_counter_std++;                                                                                        // erhöhe Stundenzähle + 1
   g_BSZ_counter_min = 0;                                                                                      // setze Minutenzähler auf 0
  }
  g_minute_vergangen = g_minute_aktuell;
}

//-------------------------------------------------------------Funktion I2C to Arduino 2 for SD Card write-------------------------------------------------------------------------------------------------
//   logFile(logtype Error,SMS_Versand, logtext zB Fehlercode,Handynummer, + Timestamp)
void logFile(String logtype,String logtext)
{   
    //Übertrage den Header Logtype
    int len = logtype.length();           					        // ermittle Stringlänge
    char StringBuf_h[len+1];               						// Buffer für String to char Array +1 für CR
    logtype.toCharArray(StringBuf_h,len+1);
    Wire.beginTransmission(4); 							        // transmit to device #4
    byte buffer_h[len+1];                                                               // Übertrage string byteweise
    for (int i=0;i<=len;i++)                                                            // übertrage byteweise
    {
      buffer_h[i] =StringBuf_h[i];
      Wire.write(buffer_h[i]);                                                            
   }
    Wire.endTransmission();  
    delay(100);
    //Übertrage den Body Logtext
    len = logtext.length();           				        	        // ermittle Stringlänge
    char StringBuf_b[len+1];               						// Buffer für String to char Array +1 für CR
    logtext.toCharArray(StringBuf_b,len+1);
    Wire.beginTransmission(4); 							        // transmit to device #4
    byte buffer_b[len+1];                                                               // Übertrage string byteweise
    for (int i=0;i<=len;i++)                                                            // übertrage byteweise
    {
      buffer_b[i] =StringBuf_b[i];
      Wire.write(buffer_b[i]);                                                            
   }
    Wire.endTransmission();  
	delay(100);

}



//-------------------------------------------------------------Funktion Ermittle die WIndgeschwindigkeit-------------------------------------------------------------------------------------------------
 float WindSpeed()
 {
    byte state = 0; // 5 bedeutet Ausstieg mit -1
	const unsigned long waiting = 1000000; //µS von Wartezeit auf Signalflankenänderung
	unsigned long time = micros(); // aktuelle Zeit in µS
	unsigned long duration1 = 0, duration2=0; // Impulslängen in µS entweder vom HIGH oder LOW Signal
	// Umfang Kreisbahn für Windmessschale => U = 2.pi.R = 2.pi.0,08m =>0,5m==>500mm==500000µm (notwendig damit gleich durch µS dividiert werden kann )
	const unsigned long Umfang = 500000;
	float wind; // windgeschwindigkeit
	boolean Flankenstate = false;
	boolean TimeOut = false; // TimeOut true bei Zeitüberschreitung
	boolean exit = false; // Swith While Schleifen Ausstieg bei true und wenn State = 5 oder State = 4 und Berechnung abgeschlossen
	
	     //   +---+  +---+  +----+  +----+  +----+
         //   |   |  |   |  |    |  |    |  |    |
         // --+   +--+   +--+    +--+    +--+    +----
		 //	  |       |
		 //   1. Flanke beginn der Zeitmessung für Windgeschwindigkeit (case 1) ( in diesen Beispiel gilt die HIGH Flanke - LOW Flanke geht genau so....)
		 //           |
		 //           3. Flanke welches das Ende des Signales beschreibt und hier wird die Endzeit ermittelt ( case 3)
		 // (case 2) misst die zB die Pulsdauer entweder vom High oder LOW signal
		 
		 
	Flankenstate = digitalRead(2); // lese aktuellen Signalzustand ein
	while(Flankenstate == digitalRead(2) && !TimeOut) // Schleife wird so lange ausgeführt, bis Signalwechsel oder TimeOut erfolgt ist
	{
		if((micros()-time)>=waiting) // bei Zeitüberschreitung 
		{
			TimeOut=true;
			state = 5; //Ausstieg mit return = -1
		}
		else
		{
			TimeOut = false;
		}	
	}
	if(state==0)
	{
		state=1; // wenn Flankenwechsel erkannt wurde gehe in die switch case
	}
	else
	{
		state = 5; //Ausstieg mit return = -1
	}
	while (!exit) // Ausstieg bei State = 5 und Returnmeldung von wind = -1
	{
		switch (state)
		{
			case 1:	// Messe die Startzeit
				time = micros();
				state=2;
				TimeOut = false; 
				Flankenstate = digitalRead(2);
				break;
			case 2: // Warte auf Flankenwechsel und messe die Endzeit und berechne die Periodendauer1
				while(Flankenstate == digitalRead(2) && !TimeOut)
				{
					if((micros()-time)>=waiting) // bei Zeitüberschreitung 
					{
						TimeOut=true;
						state = 5; //Ausstieg mit return = -1
					}
					else
					{
						TimeOut = false;
					}	
				}
				if(state!=5)
				{
					state=3; // Flankenwechsel wurde erkannt 
					duration1 = micros()-time; // Periodendauer 1 vom Signal
					time = micros(); // neue Startzeit für Periodendauer 2
				}
				else
				{
					state = 5; //Ausstieg mit return = -1
				}
				break;
			case 3: // Warte auf Flankenwechsel und messe die Endzeit und berechne die Periodendauer2
				while(Flankenstate == digitalRead(2) && !TimeOut)
				{
					if((micros()-time)>=waiting) // bei Zeitüberschreitung 
					{
						TimeOut=true;
						state = 5; //Ausstieg mit return = -1
					}
					else
					{
						TimeOut = false;
					}		
				}
				if(state!=5)
				{
					state=4; // Flankenwechsel wurde erkannt 
					duration2 = micros()-time; // Periodendauer 1 vom Signal
					time = micros(); // neue Startzeit für Periodendauer 2
				}
				else
				{
					state = 5; //Ausstieg mit return = -1
				}
				break;	
			case 4: // Berechen die Windgeschwindigkeit
				// Umfang Kreisbahn für Windmessschale => U = 2.pi.R = 2.pi.0,08m =>0,5m==>500mm==500000µm (notwendig damit gleich durch µS dividiert werden kann )
				wind = float(Umfang) / float(duration1+duration2)*3.6/4.9; //Ergebnis in km/h 4,9 Korrekturfaktor
				exit = true;// switch while schleifen Ausstiegsbedingung wenn true
				break;
			case 5: // kein Wind und daher TimeOut und return wind mit -1
				wind = 0;
				exit = true; // switch while schleifen Ausstiegsbedingung wenn true
				break;
			default:
				break;
		}
	}
	if (wind<100) // Filter sodass die max messbare Windgeschwindigkeit 99km/h ist. Teilweise gibt es Störungen auf der Leitung, dass Windgeschw. bis zu >1000km/h gemessen werden
	{
		return wind;
	}
 }

//-------------------------------------------------------------Funktion für I2C Display Übertragung----------------------------------------------------------------------
void I2CLCD()
{
  g_lcd_loop++;
  
  if (g_lcd_loop >=10)	//nach ca 5 Sekunden oder 10 CounterLoop Schleifen durchläufen
  {
	g_LCD++;
	g_lcd_loop=0;
  }
  
  switch (g_LCD)
  {
    // ||||||||||||||||  // Screen 1
    // Wind 12,2m/s NNO
    // Temp:21,2°C 88%
	case 1:
		  lcd.clear();
		  lcd.setCursor ( 0, 0 );        // ( Spalte / Zeile )
		  lcd.print("Wind:");  
		  lcd.setCursor ( 5, 0 );        
		  lcd.print (g_wind); 
		  lcd.setCursor ( 9,0 );  
		  lcd.print ("km/h "); 
		  lcd.setCursor ( 13,0 ); 
		  lcd.print (g_richtung); 
		  lcd.setCursor ( 0, 1 );
		  lcd.print ("Temp:"); 
		  lcd.setCursor ( 5, 1 );       
		  lcd.print (g_temperature); 
		  lcd.setCursor ( 10, 1 );
		  lcd.print("C");
		  lcd.setCursor ( 13, 1 );
		  lcd.print(g_humidity);
		  lcd.setCursor ( 15, 1 );
		  lcd.print("%");
		  break;
		  
    // ||||||||||||||||  // Screen 2
    // Durschnitt 30min
    // Wind  23,23m/s
	case 2:
		lcd.clear();
		lcd.setCursor ( 0, 0 );        // ( Spalte / Zeile )
		lcd.print("Durschnitt 30min");  
		lcd.setCursor ( 0, 1 );        
		lcd.print ("Wind:"); 
		lcd.setCursor ( 5,1 );  
		lcd.print (g_wind30);
		lcd.setCursor ( 9,1 );  
        lcd.print ("km/h");		
		break;
		
    // ||||||||||||||||  // Screen 3
    // Durschnitt  1Std 
    // Wind  10,23m/s
	
	case 3:
		lcd.clear();
		lcd.setCursor ( 0, 0 );        // ( Spalte / Zeile )
		lcd.print("Durschnitt 1Std");  
		lcd.setCursor ( 0, 1 );        
		lcd.print ("Wind:"); 
		lcd.setCursor ( 5,1 );  
		lcd.print (g_wind60);
		lcd.setCursor ( 9,1 );  
        lcd.print ("km/h");
		break;
	// ||||||||||||||||  // Screen 4
    // Durschnitt  3Std 
    // Wind   5,23m/s
	
	case 4:
		lcd.clear();
		lcd.setCursor ( 0, 0 );        // ( Spalte / Zeile )
		lcd.print("Durschnitt 3Std");  
		lcd.setCursor ( 0, 1 );        
		lcd.print ("Wind:"); 
		lcd.setCursor ( 5,1 );  
		lcd.print (g_wind180);
		lcd.setCursor ( 9,1 );  
        lcd.print ("km/h");
		break;
    // ||||||||||||||||  // Screen 5
    // max Wind Speed 
    // 30min v=23,23m/s
	
	case 5:
		lcd.clear();
		lcd.setCursor ( 0, 0 );        // ( Spalte / Zeile )
		lcd.print("max Wind Speed");  
		lcd.setCursor ( 0, 1 );        
		lcd.print ("30min v="); 
		lcd.setCursor ( 8,1 );  
		lcd.print (g_vmax30);
		lcd.setCursor ( 12,1 );  
        lcd.print ("km/h");
		break;
	// ||||||||||||||||  // Screen 6
    // max Wind Speed 
    // 60min v=23,23m/s
	case 6:
		lcd.clear();
		lcd.setCursor ( 0, 0 );        // ( Spalte / Zeile )
		lcd.print("max Wind Speed");  
		lcd.setCursor ( 0, 1 );        
		lcd.print ("60min v="); 
		lcd.setCursor ( 8,1 );  
		lcd.print (g_vmax60);
		lcd.setCursor ( 12,1 );  
        lcd.print ("km/h");
		break;
	// ||||||||||||||||  // Screen 7
    // Empfang(RSSI)=23
    // Netz ="bob"
	
	case 7:
		lcd.clear();
		lcd.setCursor ( 0, 0 );        // ( Spalte / Zeile )
		lcd.print("Empfang(RSSI)=");  
		lcd.setCursor ( 14, 0 );        
		lcd.print (g_rssi_val); 
		lcd.setCursor ( 0,1 );  
		lcd.print ("Netz =");
		lcd.setCursor ( 6,1 );  
        lcd.print (g_Netzbetreiber);
		break;
	// ||||||||||||||||  // Screen 8
    // Betriebsstunden
    // Std:123456789:59
	
	case 8:
		lcd.clear();
		lcd.setCursor ( 0, 0 );        // ( Spalte / Zeile )
		lcd.print("Betriebsstunden");  
		lcd.setCursor ( 0, 1 );        
		lcd.print ("Std:"); 
		lcd.setCursor ( 4,1 );  
		lcd.print (g_BSZ_counter_std);
		lcd.setCursor ( 13,1 );  
        lcd.print (g_BSZ_counter_min);
		break;
	// ||||||||||||||||  // Screen 9
    // MFC Siegendorf 
    // DSchneider v0.09
	
	case 9:
		lcd.clear();
		lcd.setCursor ( 0, 0 );        // ( Spalte / Zeile )
		lcd.print("MFC Siegendorf ");  
		lcd.setCursor ( 0, 1 );        
		lcd.print ("DSchneider v1.0"); 
		g_LCD=0;
		break;
		
	default:
		//error Code Ausgabe
		break;
  }
}

//-------------------------------------------------------------Funktion für Watchdog Arduino 2---------------------------------------------------------------------------
void Watchdog()
{
	switch (g_state)
	{
		case 1://Zustand Arduino 2 ist AUS
			if (digitalRead(ONPin)==HIGH)
			{
				g_state=2;
				//Serial.print("State");Serial.println(g_state);
			}
			break;
		
		case 2://Arduino 2 ist eingeschaltet
			
			if (digitalRead(ONPin)==HIGH)
			{
				g_state=3;
				//Serial.print("State");Serial.println(g_state);
			}
			break;
		
		case 3: //Arduino 2 ist running
			if (g_runningCount >= 2)
			{
				g_runningCount = 0;
			}
			else 
			{
				g_kill++;
				// Serial.print("g_kill ");
				// Serial.println(g_kill);
			}
			if (g_kill >=2 )
			{
				g_kill = 0;
				g_state = 4;
				//Serial.println("Reset");
			}
			break;
		
		case 4: // Reset wird durchgeführt;
			digitalWrite(Reset,HIGH); //  High Impuls steuert Transistor an welcher auf Masse durchschaltet
			delay(10);
			digitalWrite(Reset,LOW);
			g_state=1;
			g_runningCount = 0;
			break;
		
		default: //
			break;
	}

}

//-------------------------------------------------------------Funktion für WerteArchiv---------------------------------------------------------------------------------
void WerteArchiv()
{
    // Serial.print("g_ArchivCounter ");
	// Serial.println(g_ArchivCounter);
	if (!g_Archiv_first_Start) // wird true beim ersten Archivaufruf bis zum Neustart des Arduinos
	{
		g_Archiv_first_Start=true;
		g_state_archiv = 1;
	}
	
	switch (g_state_archiv)
	{
		case 1: //Init Archiv
			g_ArchivCounter = 1;
			g_state_archiv  = 2;
			g_wind_archiv30 = 0; // setze Variable für Durschnittsbildung auf 0
			g_wind_archiv60 = 0; // setze Variable für Durschnittsbildung auf 0
			g_wind_archiv180= 0; // setze Variable für Durschnittsbildung auf 0
			g_wind_max30 = 0;
			g_wind_max60 = 0;
			// Serial.println("in case 1 Werte ");
			break;
		
		case 2: // Archiv ist AN
			g_state_archiv = 3;
			g_wind_max30 = g_wind;
			g_wind_max60 = g_wind;
			// Serial.println("in case 2 Werte ");
			break;
			
		case 3: // Run Mode Archiv 30min 60min 180min
			//g_wind_archiv[g_ArchivCounter]=g_wind; // Schreibe aktuellen Messwert in array von g_wind_archiv
			// Serial.println("in case 3 Werte ");
			if (g_wind_max30 < g_wind)
			{
				g_wind_max30 = g_wind;
				g_vmax30_pre = g_wind_max30;
				//g_vmax60_pre = g_wind_max;
			}
			if (g_wind_max60 < g_wind)
			{
				g_wind_max60 = g_wind;
				g_vmax60_pre = g_wind_max60;
			}
			if (g_ArchivCounter <30) //Archivwerte werden erst berechnet
			{
				g_calc_archiv = true;	// Schaltet Led für Archivberechnung wieder aus
			}
			else
			{
				g_calc_archiv = false; // Schaltet Led für Archivberechnung wieder aus
			}
			// 30min Archiv
			if (g_ArchivCounter ==30 || g_ArchivCounter ==60 || g_ArchivCounter ==90 || g_ArchivCounter ==120 || g_ArchivCounter >=160 ) // bei folgenden Minutenwerten werde die Archive geschrieben
			{
				g_vmax30 = g_vmax30_pre;
				g_wind30 = g_wind_archiv30 / 30;
			}
			if (g_ArchivCounter ==31 || g_ArchivCounter ==61 || g_ArchivCounter ==91 || g_ArchivCounter ==121 || g_ArchivCounter >=161 ) // bei folgenden Minutenwerten werden die Archivübergabevar zurück gesetzt
			{
				g_wind_archiv30 = 0;
				g_vmax30_pre = 0;
				g_wind_max30 = 0;
			}
			//60 min Archiv
			if (g_ArchivCounter ==60 || g_ArchivCounter ==120 || g_ArchivCounter ==180 ) // bei folgenden Minutenwerten werde die Archive geschrieben
			{
				g_vmax60 = g_vmax60_pre;
				g_wind60 = g_wind_archiv60 / 60;
			}
			if (g_ArchivCounter ==61 || g_ArchivCounter ==121 || g_ArchivCounter ==181 ) // bei folgenden Minutenwerten werden die Archivübergabevar zurück gesetzt
			{
				g_wind_archiv60 = 0;
				g_vmax60_pre = 0;
				g_wind_max60 = 0;
			}
			// 180min Archiv
			if (g_ArchivCounter >= 180)
			{
				g_wind180 = g_wind_archiv180 / 180;
			}	

			if (g_ArchivCounter >= 181 ) // 181min vergangen stelle die Archive zurück
			{
				g_state_archiv = 4; //Reset Archiv
			}
			break;
		
		case 4:	//Reset Mode
			// Serial.println("in case 4 Werte ");
			if (g_ArchivCounter >= 181 ) //vergewissere mich dass ArchivCounter wirklich größer gleich 181 min hat
			{
				g_state_archiv = 1;
			}
			break;
			
		default:
			
			break;
	}
}


